/* 
 * Copyright (c)	Insighten Intelligent Equipment co.,LTD
 * 
 *  Use of this software is controlled by the terms and conditions found
 *  in the license agreement under which this software has been supplied.
 * 
 */
/** 
 * @file communication.c
 * @brief use message and share memory to communicate between processes.
 * @author taco [tacoee@gmail.com]
 * @version 0.1
 * @date 2010-09-14
 */

#include "message.h"
#include "shrmem.h"
#include "types.h"
#include "rwbuf.h"

#include "communication.h"

struct _CommObj {
	long lmtype;	/*local message type*/	
	long rmtype;	/*remote message type*/
	int ref;
	Message *msg;
	ShareMem *sm;
};

typedef struct _PrivMsg {
	long des;
	int src;
	int offset;
	int lenght;
	MsgCmd cmd;
	int ret;
	char extra[128];
} PrivMsg;

CommObj *comm_obj_create(int m_key, int s_key, int s_size)
{
	CommObj *thiz = NULL;

	thiz = calloc(sizeof(CommObj), 1);

	if (thiz != NULL) {
		thiz->msg = msg_create(m_key, sizeof(PrivMsg));
		thiz->sm = shm_create(s_key, s_size);
		thiz->ref = 0;
		thiz->lmtype = 0;
	}

	return thiz;
}

Ret comm_obj_destory(CommObj *thiz)
{
	return_val_if_fail(thiz != NULL, RET_FAIL);

	if (thiz->msg) {
		msg_destory(thiz->msg);
	}
	if (thiz->sm) {
		shm_destory(thiz->sm);
	}

	free(thiz);

	return RET_OK;
}

CommObj *comm_obj_open(CommObj *thiz, int m_key, int s_key, int s_size)
{

	if (!thiz) {
		thiz = comm_obj_create(m_key, s_key, s_size);
	} 

	thiz->ref++;

	return thiz;
}

Ret comm_obj_set_msg_type(CommObj *thiz, long lmtype, long rmtype)
{
	return_val_if_fail(thiz != NULL, RET_FAIL);
	
	if(lmtype > 0) {
		thiz->lmtype = lmtype;
	}
	if(rmtype > 0) {
		thiz->rmtype = rmtype;
	}

	return RET_FAIL;
}
Ret comm_obj_close(CommObj *thiz)
{
	return_val_if_fail(thiz != NULL, RET_FAIL);

	thiz->ref--;

	if(thiz->ref <= 0) {
		msg_destory_deeply(thiz->msg);
		shm_destory_deeply(thiz->sm);
		thiz->msg = NULL;
		thiz->sm = NULL;
		comm_obj_destory(thiz);
		thiz = NULL;
	}

	return RET_OK;
}
/*tcp client*/
Ret comm_obj_rcv_snd(CommObj *thiz, FunDataProc data_proc)
{
	return_val_if_fail(thiz != NULL && thiz->msg != NULL &&
			thiz->sm != NULL, RET_FAIL);

	if (thiz->ref <= 0) {
		return RET_REMOVE;
	}
	
	int offset;
	int lenght;
	int ret = -1;
	MsgCmd cmd;
	RwBuf *original = NULL;
	RwBuf *result	= NULL;
	Message *msg = thiz->msg;
	ShareMem *shm = thiz->sm;
	PrivMsg *pmsg = (PrivMsg *)(thiz->msg->msg_t);

	msg_rcv(msg, thiz->lmtype); /*rcv local type message*/
	dbg_log("msg->msg_t_len= %d", msg->msg_t_len);
	dbg_log("sizeof(PrivMsg)= %d", sizeof(PrivMsg));
	dbg_log("pmsg->des = %d", pmsg->des);
	dbg_log("pmsg->src = %d", pmsg->src);
	dbg_log("pmsg->cmd = %d", pmsg->cmd);
	dbg_log("pmsg->ret = %d", pmsg->ret);
	dbg_log("pmsg->offset = %d", pmsg->offset);
	dbg_log("pmsg->lenght = %d", pmsg->lenght);
	offset = pmsg->offset;
	lenght = pmsg->lenght;
	cmd = pmsg->cmd;

	original = buf_new(NULL, NULL);
	buf_init(original, lenght);

	dbg_log("shm->key = 0x%x", thiz->sm->key);
	dbg_log("shm->mid = %d", thiz->sm->mid);
	dbg_log("shm->mem_size = %d", thiz->sm->mem_size);
	shm_read(shm, offset, original->mem, lenght);
	*(original->mem+lenght) = '\0';
	dbg_log("share memory read= %s", original->mem);
	buf_update_wpos(original, lenght);
	/*use callback funcation to process data*/
	dbg_log("original address= 0x%x", original);
	dbg_log("original->mem address= 0x%x", original->mem);
	ret = data_proc(&original, &result, cmd);	
	if (ret == RET_OK) {
		dbg_log("lenght = %d", lenght);
		offset = 0;
		dbg_log("result address= 0x%x", result);
		dbg_log("result->mem address= 0x%x", result->mem);
		shm_write(shm, offset, result->mem, lenght);
	}
	pmsg->src = pmsg->des;
	pmsg->des = thiz->rmtype;
	pmsg->ret = ret;
	msg_send(msg);
	buf_destroy(original);

	return RET_OK;
}

/*osd endpoint*/
Ret comm_obj_snd_rcv(CommObj *thiz, FunDataProc data_proc, RwBuf *original)
{
	return_val_if_fail(thiz != NULL && thiz->msg != NULL &&
			thiz->sm != NULL && original != NULL, RET_FAIL);
	
	if (thiz->ref <= 0) {
		return RET_REMOVE;
	}

	int offset;
	int lenght;
	int ret;
	MsgCmd	cmd;

	RwBuf *result	= NULL;
	Message *msg = thiz->msg;
	ShareMem *shm= thiz->sm;
	PrivMsg *pmsg = (PrivMsg *)(thiz->msg->msg_t);

	offset = pmsg->offset = 0;
	lenght = pmsg->lenght = original->wpos;
	shm_write(shm,offset, original->mem, lenght);
	pmsg->src = thiz->lmtype;
	pmsg->des = thiz->rmtype;
	dbg_log("pmsg->offset = %d pmsg->lenght = %d ", pmsg->offset, pmsg->lenght);
	msg_send(msg);
	msg_rcv(msg,thiz->lmtype);
	offset = pmsg->offset;
	lenght = pmsg->lenght;
	ret = pmsg->ret;
	cmd = pmsg->cmd;
	if (ret == RET_OK) {
		memset(original->mem, 0, lenght);
		shm_read(shm, offset, original->mem, lenght);
		/*use callback funcation to process data*/
		ret = data_proc(&original, &result, cmd);	
	}

	return ret;
}
